package org.zoomdev.zoom.aop.impl;

import org.zoomdev.zoom.aop.Interceptor;
import org.zoomdev.zoom.aop.Invoker;
import org.zoomdev.zoom.aop.MethodInvokerFactory;
import org.zoomdev.zoom.common.utils.Classes;

import java.lang.reflect.Method;

public final class InterceptorChan implements Invoker {

    private final Interceptor interceptor;

    private final Invoker invoker;

    private final Method method;

    public InterceptorChan(Interceptor interceptor, Invoker invoker, Method method) {
        this.interceptor = interceptor;
        this.invoker = invoker;
        this.method = method;
    }

    public static Invoker make(Interceptor[] interceptors, Method method, Method oldMethod, MethodInvokerFactory factory) {
        Invoker invoker = factory.create(method);
        for (int i = interceptors.length - 1; i >= 0; --i) {
            invoker = new InterceptorChan(interceptors[i], invoker, oldMethod);
        }
        return invoker;
    }

    public Invoker getInvoker(Class<?> interceptorClass) {
        if (interceptor.getClass() == interceptorClass) {
            return this;
        }

        if (invoker instanceof InterceptorChan) {
            return ((InterceptorChan) invoker).getInvoker(interceptorClass);
        }

        return null;
    }

    public Interceptor getInterceptor() {
        return interceptor;
    }

    public Invoker getInvoker() {
        return invoker;
    }

    public Method getMethod() {
        return method;
    }

    @Override
    public Object invoke(Object target, Object[] args) throws Throwable {
        try {
            return interceptor.intercept(invoker, method, target, args);
        } catch (Throwable t) {
            throw Classes.getCause(t);
        }
    }


    @Override
    public String toString() {
        return "Invoke:" + invoker.toString() + " Interceptor:" + interceptor.toString();
    }
}
